winbrew_cli\services\bootstrap/
logging.rs1use anyhow::{Context, Result};
9use std::path::Path;
10use std::sync::OnceLock;
11use tracing_subscriber::{EnvFilter, fmt, prelude::*};
12
13static LOG_GUARD: OnceLock<tracing_appender::non_blocking::WorkerGuard> = OnceLock::new();
14static LOG_INIT: OnceLock<()> = OnceLock::new();
15
16pub fn init(log_dir: &Path, log_level: &str, file_log_level: &str) -> Result<()> {
24 if LOG_INIT.get().is_some() {
25 return Ok(());
26 }
27
28 std::fs::create_dir_all(log_dir)
29 .with_context(|| format!("failed to create log directory at {:?}", log_dir))?;
30
31 let file_appender = tracing_appender::rolling::daily(log_dir, "winbrew.log");
32 let (file_writer, guard) = tracing_appender::non_blocking(file_appender);
33 let _ = LOG_GUARD.set(guard);
34
35 let console_filter = EnvFilter::try_new(log_level).context("invalid core.log_level")?;
36 let file_filter = EnvFilter::try_new(file_log_level).context("invalid core.file_log_level")?;
37
38 let console_layer = fmt::layer()
39 .with_target(false)
40 .without_time()
41 .with_filter(console_filter);
42
43 let file_layer = fmt::layer()
44 .with_target(true)
45 .with_thread_ids(true)
46 .with_ansi(false)
47 .with_writer(file_writer)
48 .with_filter(file_filter);
49
50 tracing_subscriber::registry()
51 .with(console_layer)
52 .with(file_layer)
53 .try_init()
54 .context("failed to initialize tracing subscriber")?;
55
56 let _ = LOG_INIT.set(());
57
58 Ok(())
59}